#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <stdio.h>
#include <iostream>
#include <vector>
#include "math.h"
#include <fstream>
#include <iostream>
#include <utility>
#include <algorithm>
#include <math.h>
#include <iostream>
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <iterator>
#include <vector>
#include <iostream>
#include <sstream>
#include <string>
#include <cstdlib>
#include "math.h"
#include <stdio.h>
#include <time.h>
#include <algorithm>
//#include <curses.h>
#include "TROOT.h"
#include "TFile.h"
#include "TF1.h"
#include <TStyle.h>
#include <TSystem.h>
#include <TChain.h>
#include "TCanvas.h"
#include "TH1F.h"
#include "TLegend.h"
#include "AnalyzeSA.h"
#include <TH2.h>
#include <TStyle.h>
#include <TCanvas.h>
#include "TObject.h"
#include "TClonesArray.h"
#include "TChain.h"
#include "TString.h"
#include "THStack.h"
#include "TLegend.h"
#include "TPaveText.h"
#include "TLorentzVector.h"
#include "TVector3.h"
#include "Math/GenVector/VectorUtil.h"
#include "Math/Vector3D.h"
#include "Math/Vector4D.h"
#include "Math/Point3D.h"
#include "TH2.h"
#include "TH1.h"
#include "TH2F.h"
#include "TH1F.h"
#include "ExRootAnalysis/ExRootAnalysis/ExRootClasses.h"
#include "ExRootAnalysis/ExRootAnalysis/ExRootTreeReader.h"
#include "ExRootAnalysis/ExRootAnalysis/ExRootTreeWriter.h"
#include "ExRootAnalysis/ExRootAnalysis/ExRootTreeBranch.h"
#include "ExRootAnalysis/ExRootAnalysis/ExRootResult.h"
#include "ExRootAnalysis/ExRootAnalysis/ExRootUtilities.h"
/*
 #include "ExRootAnalysis/ExRootClasses.h"
 #include "ExRootAnalysis/ExRootTreeReader.h"
 #include "ExRootAnalysis/ExRootTreeWriter.h"
 #include "ExRootAnalysis/ExRootTreeBranch.h"
 #include "ExRootAnalysis/ExRootResult.h"
 #include "ExRootAnalysis/ExRootUtilities.h"
 */
#include "TApplication.h"
#include "observables.h"
#include "filters.h"
#include "jetclustering.h"
#include "hWW.h"
#include "utility.h"
//#include "services.h"
#include "TRandom1.h"
#include "TRandom2.h"
#include "TRandom3.h"
#include "TStopwatch.h"
#include "TF1.h"
#include "TUnuran.h"
#include "TUnuranContDist.h"

using namespace std;

//****************************************************************************
void memberstoevaluate(vector<vector<int> > & toevaluate,
		vector<vector<int> > classmembers,
		vector<vector<vector<int> > > allkplets, int k, int riga) {
	//****************************************************************************
	int colonna = 0;
	while (colonna < allkplets[k - 1][riga].size()) {
		toevaluate.push_back(classmembers[allkplets[k - 1][riga][colonna] - 1]);
		colonna++;
	}
} //EndOf memberstoevaluate

//****************************************************************************
void memberstoevaluatesimple(vector<vector<int> > & toevaluate,
		vector<vector<int> > classmembers, vector<vector<int> > allkplets,
		int riga) {
	//****************************************************************************
	int colonna = 0;
	while (colonna < allkplets[riga].size()) {
		toevaluate.push_back(classmembers[allkplets[riga][colonna] - 1]);
		colonna++;
	}
} //EndOf memberstoevaluatesimple

/***********************************/
/***********************************/
//typedef long double (*FUN)(vector<int> , TLorentzVector[], TRootLHEFParticle*[]);
//vector<TLorentzVector> vec_part, vector<TRootLHEFParticle*> part
typedef long double (*FUN)(vector<vector<int> >, vector<TLorentzVector>,
		vector<TRootLHEFParticle*>);
typedef vector<vector<int> > (*FIL)(vector<vector<int> >, vector<vector<int> >,
		vector<TLorentzVector>, vector<TRootLHEFParticle*>, string);

// the type for the pointers to functions of such arguments
/***********************************/
/***********************************/

//*************************************************
//vector<float> computeOBSonthekplet(TRootLHEFParticle *LHEparticles[], TLorentzVector vec_part[], vector<vector<vector<int> > > allkplets, int k, vector<int> classmembers, FUN OBS) {
vector<float> computeOBSonthekplet(vector<TRootLHEFParticle*> LHEparticles,
		vector<TLorentzVector> vec_part,
		vector<vector<vector<int> > > allkplets, int k,
		vector<vector<int> > classmembers, FUN OBS) {
	//*************************************************

	vector<float> results;
	int riga = 0;
	//cout<<"numero di "<<k<<"-etti="<<allkplets[k-1].size()<<endl;
	//cout<<allkplets[k-1].empty()<<endl;

	while (riga < allkplets[0].size()) {

		vector < vector<int> > toevaluate;
		//find the current members to evaluate
		// if it was asked for 0 members do it for all the elements in the class
		// this is typically what you want for the missing energy

		memberstoevaluate(toevaluate, classmembers, allkplets, 1, riga);

		//results.push_back(OBS(toevaluate, vec_part));
		float value;
		value = OBS(toevaluate, vec_part, LHEparticles);
		//value.push_back(w);
		results.push_back(value);
		riga++;

	}
	return results;
} //EndOf compute()


vector<int> arrange_kplet( vector<int> kplet_before_arrangers,
		vector<vector<int> > classmembers, vector<string> kplet_arrangers,
		vector<TRootLHEFParticle*> LHEparticles,
		vector<TLorentzVector> vec_part) {

	vector<int> kplet_after_arrangers;

	// nothing done till here
	return kplet_before_arrangers;
} //end of arrange_kplet

//*************************************************
//vector<float> computeOBSonthekplet(TRootLHEFParticle *LHEparticles[], TLorentzVector vec_part[], vector<vector<vector<int> > > allkplets, int k, vector<int> classmembers, FUN OBS) {
vector<float> computeOBSonthekpletsimple(
		vector<TRootLHEFParticle*> LHEparticles,
		vector<TLorentzVector> vec_part, vector<vector<int> > allkplets,
		vector<vector<int> > classmembers,
		FUN OBS) {
	//*************************************************
	/* return a vector of observable's values from a vector of kplets
	 * this applyies to the case of simple particles when the kplets is a 1-plet
	 * it always needs the translation done through classmembers
	 * */

	vector<float> results;
	int riga = 0;
	//cout<<"numero di "<<k<<"-etti="<<allkplets[k-1].size()<<endl;
	//cout<<allkplets[k-1].empty()<<endl;

	while (riga < allkplets.size()) {
		// toevaluate is a list of lists
		// each object is a composite

		vector < vector<int> > toevaluate;
		//  find the current members to evaluate
		//  if it was asked for 0 members do it for all the elements in the class
		//  this is typically what you want for the missing energy

		//  before computing the observable the particle involved in the computation can be rearranged with an arranger
	    //	vector<int> kplet_before_arrangers = allkplets[riga];
	    //	vector<int> kplet_after_arrangers;

		//kplet_after_arrangers = arrange_kplet(kplet_before_arrangers,	classmembers, kplet_arrangers, LHEparticles, vec_part);

		/* translates each k-plet in the cardinal notation 1,2,3, in lines in the event, Event Notation*/
		memberstoevaluatesimple(toevaluate, classmembers, allkplets, riga);

		//results.push_back(OBS(toevaluate, vec_part));
		float value;
		value = OBS(toevaluate, vec_part, LHEparticles);

		//value.push_back(w);
		results.push_back(value);
		riga++;

	}
	return results;
} //EndOf compute()
